use self::{fitnesers::destroyer::Destroyer, options::Options};
use log::error;
use std::{
  sync::{mpsc::Sender, Arc, Mutex},
  thread::sleep,
  time::Duration,
};

use super::window::Window;
use fitnesers::walk::Walk;
use fitnesers::wheel_barrow::WheelBarrow;
use fitnesers::Fitneser;

mod fitnesers;
pub mod options;

pub struct Fitness {
  assets_path: String,
}

impl Fitness {
  pub fn new(assets_path: String) -> Self {
    Fitness { assets_path }
  }

  pub fn start(
    &self,
    opts_mutex: Arc<Mutex<Options>>,
    state_mutex: Arc<Mutex<bool>>,
    msg_tx: Sender<String>,
  ) {
    loop {
      let _mutex = Arc::clone(&state_mutex);
      let _running = *_mutex.lock().unwrap();
      drop(_mutex);
      if !_running {
        sleep(Duration::from_millis(1000 * 1));
        continue;
      }
      let _mutex = Arc::clone(&opts_mutex);
      let _xx = _mutex.lock().unwrap();
      let _opts = _xx.to_owned();
      let _mutex = Arc::clone(&state_mutex);
      if !self.run(_opts, _mutex, &msg_tx) {
        let _ = msg_tx.send(format!("启动失败"));
        let _mutex = Arc::clone(&state_mutex);
        let mut _running = _mutex.lock().unwrap();
        *_running = false;
      }
    }
  }

  pub fn run(&self, opts: Options, _mutex: Arc<Mutex<bool>>, msg_tx: &Sender<String>) -> bool {
    let mut fitneser = self.get_fitneser(opts.r#type, Arc::clone(&_mutex));
    if let Err(e) = fitneser.init(&opts, self.assets_path.clone()) {
      let _ = msg_tx.send(format!("初始化失败: {}", e.to_string()));
      return false;
    }
    if let Ok(win) = Window::new(self.assets_path.clone()) {
      win.sleep(1000);
      loop {
        let _t_mutex = Arc::clone(&_mutex);
        let _running = *_t_mutex.lock().unwrap();
        drop(_t_mutex);
        if !_running {
          break;
        }
        if let Err(e) = fitneser.run(&win, msg_tx) {
          error!("{}", e.to_string());
          let _ = msg_tx.send(format!("err: {}", e.to_string()));
          sleep(Duration::from_millis(100));
          let _ = win.tap_key("esc");
          sleep(Duration::from_millis(250));
          let _ = win.tap_key("esc");
          sleep(Duration::from_millis(1000));
        }
      }
      return true;
    }
    return false;
  }

  /// 获取对应类型的练体器 0 小推车 1 移动
  fn get_fitneser(&self, _type: u8, mutex: Arc<Mutex<bool>>) -> Box<dyn Fitneser> {
    if _type == 0 {
      return Box::new(WheelBarrow::new(mutex));
    } else if _type == 1 {
      return Box::new(Walk::new(mutex));
    }
    return Box::new(Destroyer::new(mutex));
  }
}
